"""
Case Type   : 故障&可靠性测试
Case Name   : 开启RTO时，修改备机延迟
Create At   : 2021/03/02
Owner       : opengauss
Description :
    1.开启RTO
    2.重启集群
    3.配置recovery_min_apply_delay=2min
    4.等待主备一致
    5.创建表
    6.等待20s关闭RTO
    7.重启数据库
    8.等待主备一致
    9.查询备节点
Expect      :
    1.配置成功
    2.重启成功
    3.配置成功
    4.主备一致
    5.创建成功
    6.配置成功
    7.重启成功
    8.主备一致
    9.备节点同步
History     :
    Modified by ningyali 2024/7/9 优化用例解决一致性问题
"""
import os
import time
import unittest

from yat.test import Node

from testcase.utils.Common import Common
from testcase.utils.CommonSH import CommonSH
from testcase.utils.CommonSH import RestartDbCluster
from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger


class RecoveryDelay(unittest.TestCase):
    nodes_tuple = ('PrimaryDbUser', 'Standby1DbUser', 'Standby2DbUser')

    @RestartDbCluster(*nodes_tuple)
    def setUp(self):
        self.log = Logger()
        self.log.info(f'----{os.path.basename(__file__)} 开始执行-----')
        self.pri_sh = CommonSH(self.nodes_tuple[0])
        self.sta_sh = [CommonSH(self.nodes_tuple[1]),
                       CommonSH(self.nodes_tuple[2])]
        self.constant = Constant()
        self.tb_name = 'tb_dbsystem_251'

    def test_recoverydelay(self):
        text = '-----step1:开启极致RTO; expect:设置成功-----'
        self.log.info(text)
        for param in ('replication_type=1', 'recovery_parse_workers=4',
                      'recovery_redo_workers=4', 'hot_standby=off'):
            res = self.pri_sh.executeGsguc(
                'set', self.constant.GSGUC_SUCCESS_MSG, param)
            self.assertTrue(res, f'执行失败:{text}')

        text = '-----step2:重启数据库; expect:重启成功-----'
        self.log.info(text)
        is_stopped = self.pri_sh.stopDbCluster()
        is_started = self.pri_sh.startDbCluster()
        self.assertTrue(is_stopped and is_started, f'执行失败:{text}')

        text = '-----step3:设置recovery_min_apply_delay=2min; expect:设置成功-----'
        self.log.info(text)
        result = self.pri_sh.executeGsguc(
            'reload', self.constant.GSGUC_SUCCESS_MSG,
            'recovery_min_apply_delay=2min')
        self.assertTrue(result, f'执行失败:{text}')

        text = '-----step4:等待主备一致; expect:主备一致-----'
        self.log.info(text)
        for i in range(2):
            result = self.sta_sh[i].check_data_consistency()
            self.assertTrue(result, f'执行失败:{text}')

        text = '-----step5:创建表; expect:创建表成功，主备状态正常-----'
        self.log.info(text)
        sql = f"drop table if exists {self.tb_name};" \
              f"create table {self.tb_name}(i int, s char(10));"
        result = self.pri_sh.executDbSql(sql)
        self.log.info(result)
        self.assertIn(self.constant.TABLE_CREATE_SUCCESS, result,
                      f'执行失败:{text}')

        self.log.info('-----查询主备状态-----')
        result = self.pri_sh.getDbClusterStatus('status')
        self.assertTrue(result, f'执行失败:{text}')

        text = '-----step6:等待20s关闭RTO; expect:关闭成功-----'
        self.log.info(text)
        time.sleep(20)
        for param in ('recovery_parse_workers=1', 'recovery_redo_workers=1',
                      'hot_standby=on'):
            result = self.pri_sh.executeGsguc(
                'set', self.constant.GSGUC_SUCCESS_MSG, param)
            self.assertTrue(result, f'执行失败:{text}')

        text = '-----step7:重启数据库; expect:重启成功-----'
        self.log.info(text)
        result = self.pri_sh.stopDbCluster()
        self.assertTrue(result, f'执行失败:{text}')
        self.pri_sh.startDbCluster(True)

        text = '-----step8:等待主备一致; expect:主备一致-----'
        self.log.info(text)
        for i in range(2):
            result = self.sta_sh[i].check_data_consistency()
            self.assertTrue(result, f'执行失败:{text}')

        self.log.info('-----查询主备状态-----')
        result = self.pri_sh.getDbClusterStatus('status')
        self.assertTrue(result, f'执行失败:{text}')

        text = '-----step9:查询备节点; expect:表存在-----'
        self.log.info(text)
        sql = f"select sysdate;select * from {self.tb_name};"
        for i in range(2):
            result = self.sta_sh[i].executDbSql(sql)
            self.log.info(result)
            self.assertIn('(0 rows)', result, f'执行失败:{text}')

    def tearDown(self):
        self.log.info('-----this is tearDown-----')
        self.log.info('-----还原guc参数-----')
        res_list = list()
        for param in ('recovery_min_apply_delay=0', 'recovery_parse_workers=1',
                      'recovery_redo_workers=1', 'hot_standby=on'):
            result = self.pri_sh.executeGsguc(
                'set', self.constant.GSGUC_SUCCESS_MSG, param)
            self.log.info(result)
            res_list.append(result)

        self.log.info('-----重启数据库-----')
        result = self.pri_sh.stopDbCluster()
        self.log.info(result)
        result = self.pri_sh.startDbCluster()
        self.log.info(result)

        time.sleep(5)
        self.log.info('-----删除表-----')
        sql = f"drop table if exists {self.tb_name};"
        result = self.pri_sh.executDbSql(sql)
        self.log.info(result)

        self.assertIn(self.constant.TABLE_DROP_SUCCESS, result)
        self.assertEqual(res_list.count(True), 4)
        self.log.info(f'-----{os.path.basename(__file__)} 执行结束-----')
